/*
 * Copyright ©2021 su binglun(9085309@qq.com). All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *---------------------------------------------------------------------
 *-                                                                   -
 *-           Website : http://phoenix.sunny360.cn/                   -
 *-                                                                   -
 *---------------------------------------------------------------------
 */
package cn.sunny360.core.verticle;

import cn.sunny360.core.common.HttpHandlerMapping;
import cn.sunny360.core.common.MsgActionMapping;
import cn.sunny360.core.common.MyProperty;
import cn.sunny360.core.handler.http.DeviceHandler;
import cn.sunny360.core.handler.http.GroupHandler;
import cn.sunny360.core.handler.http.LinkmanHandler;
import cn.sunny360.core.handler.http.UserHandler;
import cn.sunny360.core.handler.msg.*;
import cn.sunny360.core.service.*;
import cn.sunny360.core.service.impl.*;
import cn.sunny360.core.utils.Container;
import cn.sunny360.core.wrapper.CacheWrapper;
import cn.sunny360.core.wrapper.DBWrapper;
import cn.sunny360.core.wrapper.impl.ConcurrentMapWrapper;
import cn.sunny360.core.wrapper.impl.MysqlClientWrapper;
import com.sohu.idcenter.IdWorker;
import io.vertx.config.ConfigRetriever;
import io.vertx.config.ConfigRetrieverOptions;
import io.vertx.config.ConfigStoreOptions;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.impl.logging.Logger;
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import java.util.Properties;


/**
 * A verticle publishing the user service.
 *
 * @author sublun
 */
public class MainVerticle extends BaseVerticle {

    private static final Logger logger = LoggerFactory.getLogger(MainVerticle.class);

    @Override
    public void start() throws Exception {
        super.start();
        Promise<String> promise = Promise.promise();
        initProperties(promise);
        promise.future().onSuccess(a -> {
            //初始化系统组件
            initComponent();
            deployVerticles();
        });

        logger.info("系统已经启动...");
    }

    private void initComponent() {




        //Tools
        //IdWorker(long workerId, long datacenterId, long sequence)
        //参数1：机器编号 参数2：数据中心编号 参数3：序列起始值
        //如果有需要多个数据服务生成id则需要配置不同的机器编号及数据中心编号，不能大于31
        //在不同的服务中使用IDWorker最好设置不同的数据中心编号，也就是第二个参数值，不能大于31
        //
        Long workerId = MyProperty.ID_WORKERID;
        Long datacenterId = MyProperty.ID_DATACENTERID;
        Long sequence = MyProperty.ID_SEQUENCE;
        IdWorker idWorker = new IdWorker(workerId, datacenterId, sequence);
        Container.putComponent(IdWorker.class, idWorker);

        //Wrappers
        DBWrapper dbWrapper = new MysqlClientWrapper(vertx);
        Container.putComponent(DBWrapper.class, dbWrapper);
        CacheWrapper cacheWrapper = new ConcurrentMapWrapper(vertx);
        Container.putComponent(CacheWrapper.class, cacheWrapper);

        //Service
        UserService userService = new UserServiceImpl();
        Container.putComponent(UserService.class, userService);
        DeviceService deviceService = new DeviceServiceImpl();
        Container.putComponent(DeviceService.class, deviceService);
        MessageService messageService = new MessageServiceImpl();
        Container.putComponent(MessageService.class, messageService);
        LinkmanService linkmanService = new LinkmanServiceImpl();
        Container.putComponent(LinkmanService.class, linkmanService);
        SystemService systemService = new SystemServiceImpl();
        Container.putComponent(SystemService.class, systemService);
        GroupService groupService = new GroupServiceImpl();
        Container.putComponent(GroupService.class, groupService);

        //HttpHandlerMapping
        final String userHandler = UserHandler.class.getName();
        final String linkmanHandler = LinkmanHandler.class.getName();
        final String groupHandler = GroupHandler.class.getName();
        final String deviceHandler = DeviceHandler.class.getName();
        HttpHandlerMapping restHandlerMapping = new HttpHandlerMapping()
                .addHandler("post", "/user/login", userHandler + "#apiUserLogin")
                .addHandler("post", "/linkman/list", linkmanHandler + "#getUserLinkmanList")
                .addHandler("post", "/linkman/add", linkmanHandler + "#addUserLinkman")
                .addHandler("post", "/linkman/remove", linkmanHandler + "#removeUserLinkman")
                .addHandler("post", "/linkman/uptime", linkmanHandler + "#updateUserLinkTime")
                .addHandler("get", "/user/id/:id", userHandler + "#getUserInfoById")
                .addHandler("get", "/user/name/:username", userHandler + "#getUserInfoByName")
                .addHandler("post", "/user/create", userHandler + "#createUser")
                .addHandler("get", "/user/role/:roleId", userHandler + "#getUserListByRole")
                .addHandler("post", "/user/update", userHandler + "#updateUser")
                .addHandler("post", "/device/register", deviceHandler + "#deviceRegister")
                .addHandler("post", "/group/list", groupHandler + "#getGroupList")
                .addHandler("post", "/group/create", groupHandler + "#createGroup")
                .addHandler("post", "/group/apply/join", groupHandler + "#applyJoinGroup")
                .addHandler("post", "/group/add/member", groupHandler + "#addGroupMember")
                .addHandler("post", "/group/approved/apply", groupHandler + "#approvedApply")
                .addHandler("post", "/group/member/list", groupHandler + "#getGroupMemberList")
                .addHandler("get", "/group/apply/list/:groupId", groupHandler + "#getApplyList");
        Container.putComponent("restHandlerMapping", restHandlerMapping);

        //MsgActionMapping
        MsgActionMapping msgActionMapping = new MsgActionMapping()
                .putAction("connection", new ConnectionAction())
                .putAction("message", new MessageAction())
                .putAction("sync", new SyncAction())
                .putAction("ack", new AckAction())
                .putAction("history", new HistoryAction());
        Container.putComponent(MsgActionMapping.class, msgActionMapping);
    }




    private void initProperties(Promise<String> promise) {
        ConfigStoreOptions propertyWithHierarchical = new ConfigStoreOptions()
                .setFormat("properties")
                .setType("file")
                .setConfig(new JsonObject().put("path", "application.properties").put("hierarchical", true).put("raw-data", true)
                );
        ConfigRetrieverOptions options = new ConfigRetrieverOptions()
                .addStore(propertyWithHierarchical);
        ConfigRetriever configRetriever = ConfigRetriever.create(Vertx.vertx(), options);

        Future<JsonObject> future = configRetriever.getConfig();
        future.onComplete(ar -> {
            if (ar.failed()) {
                logger.info("获取配置失败...");
                promise.fail("fail");
            } else {
                JsonObject config = ar.result();
                MyProperty.MYSQL_HOST = config.getJsonObject("mysql").getString("host");
                MyProperty.MYSQL_PORT = Integer.valueOf(config.getJsonObject("mysql").getString("port"));
                MyProperty.MYSQL_DATABASE=    config.getJsonObject("mysql").getString("database");
                MyProperty.MYSQL_USER=  config.getJsonObject("mysql").getString("user");
                MyProperty.MYSQL_PASSWORD=   config.getJsonObject("mysql").getString("password");
                MyProperty.MYSQL_POOL_SIZE= Integer.valueOf(config.getJsonObject("mysql").getString("pool-size"));
                MyProperty.ID_WORKERID = Long.valueOf(config.getJsonObject("id").getString("workerId"));
                MyProperty.ID_DATACENTERID =  Long.valueOf(config.getJsonObject("id").getString("datacenterId"));
                MyProperty.ID_SEQUENCE=   Long.valueOf(config.getJsonObject("id").getString("sequence"));
                MyProperty.WS_PROTOCOL= config.getJsonObject("ws").getString("protocol");
                MyProperty.USER_HTTP_PORT=  Integer.valueOf(config.getJsonObject("user").getJsonObject("http").getString("port"));
                MyProperty.USER_WS_PORT=  Integer.valueOf(config.getJsonObject("user").getJsonObject("ws").getString("port"));
                MyProperty.USER_WS_ADDRESS=   config.getJsonObject("user").getJsonObject("ws").getString("address");
                MyProperty.WS_CHAT_URL=   config.getJsonObject("ws").getJsonObject("chat").getString("url");
                promise.complete("ok");
                logger.info("获取配成功...");
            }
        });





    }


    private void deployVerticles() {
        //Verticles
        DeploymentOptions options = new DeploymentOptions().setConfig(config());
        deployVerticle(RestApiVerticle.class, options);
        deployVerticle(ChatVerticle.class, options);
    }


    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();
        JsonObject config = new JsonObject();
        //logger.debug(config);
        DeploymentOptions options = new DeploymentOptions().setConfig(config);
        vertx.deployVerticle(MainVerticle.class, options);
    }

}
